﻿#include <iostream>
#include <windows.h>
#include <conio.h>
#include <time.h>
#include <fstream>
#include <vector>
#include <string>
using namespace std;

// 定义常量
#define UP 72
#define DOWN 80
#define LEFT 75
#define RIGHT 77
#define ESC 27
#define F1 59
#define F2 60

// 全局变量
int sleeptime = 200;
int score = 0;
int add = 10;
int highscore = 0;
bool isDie = false;

struct Point {
    int x;
    int y;
};
vector<Point> snake;
Point food;
int direction = RIGHT;

// 函数声明
void printWelcomeArt();
void welcometogame();
void createMap();
void scoreandtips();
void File_out();
void File_in();
void initsnake();
void createfood();
bool biteself();
bool hitwall();
void speedup();
void speeddown();
void snakemove();
void keyboardControl();
void gameover();
void explation();
void gotoxy(int x, int y);
void color(int c);
void drawSnake();
void clearSnakeTail();
void drawGameTitle();
void drawBorder();
void drawAnimatedStart();
void drawAnimatedGameOver();
void hideCursor();

int main() {
    system("mode con cols=100 lines=30");
    system("title 贪吃蛇豪华版");
    hideCursor();
    File_in();
    welcometogame();
    return 0;
}

void hideCursor() {
    CONSOLE_CURSOR_INFO cursor_info = { 1, 0 };
    SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor_info);
}

void gotoxy(int x, int y) {
    COORD pos = { x, y };
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);
}

void color(int c) {
    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), c);
}

void printWelcomeArt() {
    color(11);
    cout << R"(
  _________   _        _________   ________   ________   ___   ________      
 /   _____/  | |       \_____  \  \_____  \  \_____  \  \  \  \_____  \     
 \_____  \   | |        /  ____/   /  ____/   /  ____/   \  \  /  ____/     
 /        \  | |___    /  /       /  /       /  /         \  \/  /          
/_________/  |_____|  /__/       /__/       /__/           \____/           
    )" << endl;
}

void drawGameTitle() {
    color(14);
    gotoxy(35, 3);
    cout << "████████╗ █████╗ ███╗   ██╗██╗  ██╗███████╗";
    gotoxy(35, 4);
    cout << "╚══██╔══╝██╔══██╗████╗  ██║██║  ██║██╔════╝";
    gotoxy(35, 5);
    cout << "   ██║   ███████║██╔██╗ ██║███████║█████╗  ";
    gotoxy(35, 6);
    cout << "   ██║   ██╔══██║██║╚██╗██║██╔══██║██╔══╝  ";
    gotoxy(35, 7);
    cout << "   ██║   ██║  ██║██║ ╚████║██║  ██║███████╗";
    gotoxy(35, 8);
    cout << "   ╚═╝   ╚═╝  ╚═╝╚═╝  ╚═══╝╚═╝  ╚═╝╚══════╝";
}

void drawBorder() {
    color(9);
    // 上边框
    for (int i = 0; i < 58; i += 2) {
        gotoxy(i, 0);
        cout << "▄";
    }
    // 下边框
    for (int i = 0; i < 58; i += 2) {
        gotoxy(i, 26);
        cout << "▀";
    }
    // 左边框
    for (int i = 1; i < 26; i++) {
        gotoxy(0, i);
        cout << "█";
    }
    // 右边框
    for (int i = 1; i < 26; i++) {
        gotoxy(56, i);
        cout << "█";
    }

    // 添加网格线
    color(8);
    for (int y = 1; y < 26; y++) {
        for (int x = 2; x < 56; x += 2) {
            gotoxy(x, y);
            cout << "·";
        }
    }
}

void drawAnimatedStart() {
    for (int i = 0; i < 3; i++) {
        color(10 + i);
        gotoxy(30, 15);
        cout << "游戏即将开始..." << string(3 - i, '.');
        Sleep(300);
    }
    system("cls");
}

void drawAnimatedGameOver() {
    system("cls");
    color(12);
    for (int i = 0; i < 3; i++) {
        gotoxy(35, 10);
        cout << "游戏结束" << string(i + 1, '!');
        Sleep(300);
    }
    Sleep(500);
}

void welcometogame() {
    system("cls");
    drawGameTitle();

    color(11);
    gotoxy(35, 12);
    cout << "1. 开始游戏";
    gotoxy(35, 13);
    cout << "2. 游戏说明";
    gotoxy(35, 14);
    cout << "3. 退出游戏";
    gotoxy(35, 15);
    cout << "4. 查看最高分";
    gotoxy(35, 17);
    cout << "请选择(1-4): ";

    char ch = _getch();
    while (ch != '1' && ch != '2' && ch != '3' && ch != '4') {
        ch = _getch();
    }

    switch (ch) {
    case '1':
        isDie = false;
        score = 0;
        add = 10;
        sleeptime = 200;
        direction = RIGHT;
        snake.clear();
        drawAnimatedStart();
        createMap();
        initsnake();
        createfood();
        keyboardControl();
        break;
    case '2':
        explation();
        break;
    case '3':
        exit(0);
        break;
    case '4':
        system("cls");
        color(10);
        cout << "最高分: " << highscore << endl;
        system("pause");
        welcometogame();
        break;
    }
}

void createMap() {
    system("cls");
    drawBorder();
}

void scoreandtips() {
    gotoxy(62, 10);
    color(14);
    cout << "╔══════════════╗";
    gotoxy(62, 11);
    cout << "║ 得分: " << score << " 分   ║";
    gotoxy(62, 12);
    cout << "║ 最高分: " << highscore << " 分 ║";
    gotoxy(62, 13);
    cout << "╚══════════════╝";

    gotoxy(62, 15);
    color(13);
    cout << "╔══════════════╗";
    gotoxy(62, 16);
    cout << "║ 操作说明:    ║";
    gotoxy(62, 17);
    cout << "║ 方向键控制   ║";
    gotoxy(62, 18);
    cout << "║ F1 加速      ║";
    gotoxy(62, 19);
    cout << "║ F2 减速      ║";
    gotoxy(62, 20);
    cout << "║ ESC 退出     ║";
    gotoxy(62, 21);
    cout << "╚══════════════╝";
}

void File_in() {
    ifstream infile("save.txt");
    if (!infile) {
        highscore = 0;
    }
    else {
        infile >> highscore;
        infile.close();
    }
}

void File_out() {
    ofstream outfile("save.txt");
    if (outfile) {
        outfile << highscore;
        outfile.close();
    }
}

void initsnake() {
    snake.clear();
    Point p;
    p.x = 20;
    p.y = 10;
    snake.push_back(p);
    p.x = 18;
    snake.push_back(p);
    p.x = 16;
    snake.push_back(p);

    drawSnake();
}

void drawSnake() {
    for (int i = 0; i < snake.size(); i++) {
        gotoxy(snake[i].x, snake[i].y);
        if (i == 0) {
            color(14); // 蛇头黄色
            cout << "◎";
        }
        else {
            color(10); // 蛇身绿色
            cout << "●";
        }
    }
}

void clearSnakeTail() {
    Point tail = snake.back();
    gotoxy(tail.x, tail.y);
    cout << "·"; // 用网格点覆盖
}

void createfood() {
    srand((unsigned)time(NULL));
    bool inSnake;
    do {
        inSnake = false;
        food.x = (rand() % 27 + 1) * 2;
        food.y = rand() % 25 + 1;

        for (int i = 0; i < snake.size(); i++) {
            if (food.x == snake[i].x && food.y == snake[i].y) {
                inSnake = true;
                break;
            }
        }
    } while (inSnake || food.x >= 56 || food.y >= 26);

    color(12);
    gotoxy(food.x, food.y);
    cout << "♥"; // 使用心形作为食物
}

bool biteself() {
    for (int i = 1; i < snake.size(); i++) {
        if (snake[0].x == snake[i].x && snake[0].y == snake[i].y) {
            return true;
        }
    }
    return false;
}

bool hitwall() {
    return (snake[0].x <= 0 || snake[0].x >= 56 || snake[0].y <= 0 || snake[0].y >= 26);
}

void speedup() {
    if (sleeptime >= 50) {
        sleeptime -= 30;
        add += 2;
    }
}

void speeddown() {
    if (sleeptime <= 350) {
        sleeptime += 30;
        if (add > 2) add -= 2;
        else add = 1;
    }
}

void snakemove() {
    Point oldTail = snake.back();
    clearSnakeTail();

    for (int i = snake.size() - 1; i > 0; i--) {
        snake[i] = snake[i - 1];
    }

    switch (direction) {
    case UP:
        snake[0].y--;
        break;
    case DOWN:
        snake[0].y++;
        break;
    case LEFT:
        snake[0].x -= 2;
        break;
    case RIGHT:
        snake[0].x += 2;
        break;
    }

    // 绘制新蛇头
    gotoxy(snake[0].x, snake[0].y);
    color(14);
    cout << "◎";

    // 重新绘制蛇身第一节（因为原来的头变成了身体）
    if (snake.size() > 1) {
        gotoxy(snake[1].x, snake[1].y);
        color(10);
        cout << "●";
    }

    if (snake[0].x == food.x && snake[0].y == food.y) {
        snake.push_back(oldTail);
        score += add;

        // 吃食物特效
        gotoxy(food.x, food.y);
        color(13);
        cout << "★";
        Sleep(100);

        scoreandtips();
        createfood();
    }

    if (hitwall() || biteself()) {
        isDie = true;
    }
}

void keyboardControl() {
    scoreandtips();
    while (!isDie) {
        if (_kbhit()) {
            int key = _getch();
            if (key == 224) {
                key = _getch();
                switch (key) {
                case UP:
                    if (direction != DOWN) direction = UP;
                    break;
                case DOWN:
                    if (direction != UP) direction = DOWN;
                    break;
                case LEFT:
                    if (direction != RIGHT) direction = LEFT;
                    break;
                case RIGHT:
                    if (direction != LEFT) direction = RIGHT;
                    break;
                }
            }
            else if (key == ESC) {
                isDie = true;
            }
            else if (key == F1) {
                speedup();
            }
            else if (key == F2) {
                speeddown();
            }
        }
        snakemove();
        Sleep(sleeptime);
    }
    gameover();
}

void gameover() {
    drawAnimatedGameOver();
    system("cls");
    if (score > highscore) {
        highscore = score;
        File_out();
        color(12);
        gotoxy(25, 10);
        cout << "创纪录啦！最高分被你刷新啦，真棒！！！";
    }
    else {
        color(11);
        gotoxy(30, 10);
        cout << "继续努力吧~你离最高分还差: " << highscore - score << " 分";
    }

    gotoxy(30, 12);
    color(14);
    cout << "你的得分: " << score << " 分";
    gotoxy(30, 14);
    cout << "最高分: " << highscore << " 分";

    gotoxy(30, 16);
    color(13);
    cout << "1. 重新开始";
    gotoxy(30, 17);
    cout << "2. 退出游戏";
    gotoxy(30, 19);
    cout << "请选择(1-2): ";

    char ch = _getch();
    while (ch != '1' && ch != '2') {
        ch = _getch();
    }

    if (ch == '1') {
        welcometogame();
    }
    else {
        exit(0);
    }
}

void explation() {
    system("cls");
    color(13);
    gotoxy(20, 5);
    cout << "游戏说明";
    gotoxy(10, 7);
    cout << "1. 使用方向键控制蛇的移动方向";
    gotoxy(10, 8);
    cout << "2. 吃到食物(♥)可以增加蛇的长度和得分";
    gotoxy(10, 9);
    cout << "3. 按F1键加速，F2键减速";
    gotoxy(10, 10);
    cout << "4. 撞到墙壁或自己的身体游戏结束";
    gotoxy(10, 11);
    cout << "5. 按ESC键可以退出游戏";
    gotoxy(10, 13);
    system("pause");
    welcometogame();
}